package main

import (
	"context"
	"fmt"
	"io/ioutil"
	"strings"

	"github.com/open-policy-agent/opa/ast"
	"github.com/open-policy-agent/opa/rego"
	"github.com/open-policy-agent/opa/storage/inmem"
)

func main() {
	ctx := context.Background()

	// build module
	rule := loadfile("rbac.rego")
	policy := "rbac"
	module, err := ast.ParseModule(policy, rule)
	if err != nil {
		panic(err)
	}
	compiler := ast.NewCompiler()
	if compiler.Compile(map[string]*ast.Module{policy: module}); compiler.Failed() {
		fmt.Printf("%v\n", compiler.Errors)
	}

	// build store
	data := loadfile("rbac.json")
	store := inmem.NewFromReader(strings.NewReader(data))

	// build query
	query, err := rego.New(
		rego.Query("data.rbac"),
		rego.Store(store),
		rego.Compiler(compiler),
	).PrepareForEval(ctx)
	if err != nil {
		panic(err)
	}

	// query1
	{
		input := map[string]interface{}{"user": "alice", "type": "dog", "action": "read"}
		rst, err := query.Eval(ctx, rego.EvalInput(input))
		if err != nil || len(rst) == 0 {
			panic(err)
		}
		fmt.Println(rst[0].Expressions[0].Value)
	}

	// query2
	{
		input := map[string]interface{}{"user": "bob", "type": "dog", "action": "read"}
		rst, err := query.Eval(ctx, rego.EvalInput(input))
		if err != nil {
			panic(err)
		}
		fmt.Println(rst[0].Expressions[0].Value)
	}

	// query3
	{
		input := map[string]interface{}{"user": "bob", "type": "dog", "action": "write"}
		rst, err := query.Eval(ctx, rego.EvalInput(input))
		if err != nil {
			panic(err)
		}
		fmt.Println(rst[0].Expressions[0].Value)
	}
}

func loadfile(f string) string {
	b, err := ioutil.ReadFile(f)
	if err != nil {
		panic(err)
	}
	return string(b)
}
